/*
* Author: Chris Seguin
*
* This software has been developed under the copyleft
* rules of the GNU General Public License. Please
* consult the GNU General Public License for more
* details about use and distribution of this software.
*/
package org.acm.seguin.pretty.ai;
import java.text.MessageFormat;
import org.acm.seguin.parser.Node;
import org.acm.seguin.parser.ast.ASTFormalParameter;
import org.acm.seguin.parser.ast.ASTFormalParameters;
import org.acm.seguin.parser.ast.ASTMethodDeclaration;
import org.acm.seguin.parser.ast.ASTMethodDeclarator;
import org.acm.seguin.parser.ast.ASTName;
import org.acm.seguin.parser.ast.ASTNameList;
import org.acm.seguin.parser.ast.ASTResultType;
import org.acm.seguin.parser.ast.ASTType;
import org.acm.seguin.parser.ast.ASTVariableDeclaratorId;
import org.acm.seguin.pretty.JavaDocableImpl;
import org.acm.seguin.util.FileSettings;
import org.acm.seguin.util.MissingSettingsException;
/**
* Basis for the artificial intelligence that analyzes the method and
* determines the appropriate javadoc descriptions
*
*@author Chris Seguin
*/
public class MethodAnalyzer
{
private ASTMethodDeclaration node;
private JavaDocableImpl jdi;
/**
* Constructor for the MethodAnalyzer object
*
*@param node Description of Parameter
*@param jdi Description of Parameter
*/
public MethodAnalyzer(ASTMethodDeclaration node, JavaDocableImpl jdi)
{
this.node = node;
this.jdi = jdi;
}
/**
* Makes sure all the java doc components are present. For methods and
* constructors we need to do more work - checking parameters, return types,
* and exceptions.
*
*@param className Description of Parameter
*/
public void finish(String className)
{
// Get the resource bundle
FileSettings bundle = FileSettings.getSettings("Refactory", "pretty");
// Require a description of this method
requireDescription(bundle, className);
String methodTags = "return,param,exception";
try {
methodTags = bundle.getString("method.tags");
}
catch (MissingSettingsException mse) {
}
// Check that if there is a return type
if (methodTags.indexOf("return") >= 0) {
finishReturn(bundle);
}
// Check for parameters
if (methodTags.indexOf("param") >= 0) {
finishParameters(bundle);
}
// Check for exceptions
if (methodTags.indexOf("exception") >= 0) {
finishExceptions(bundle);
}
}
/**
* Determine if this is a setter method
*
*@return true if it is a setter
*/
private boolean isSetter()
{
String name = getName();
return ((name.length() > 3) && name.startsWith("set") &&
Character.isUpperCase(name.charAt(3)));
}
/**
* Determine if this is a getter method
*
*@return true if it is a getter
*/
private boolean isGetter()
{
String name = getName();
return ((name.length() > 3) && (name.startsWith("get") && Character.isUpperCase(name.charAt(3))) ||
((name.length() > 2) && name.startsWith("is") && Character.isUpperCase(name.charAt(2))));
}
/**
* Determine if this is a getter method
*
*@return true if it is a getter
*/
private boolean isAdder()
{
String name = getName();
return (name.length() > 3) && (name.startsWith("add") && Character.isUpperCase(name.charAt(3)));
}
/**
* Determine if this is a run method
*
*@return true if it is a run method
*/
private boolean isRunMethod()
{
String name = getName();
return name.equals("run");
}
/**
* Gets the MainMethod attribute of the MethodAnalyzer object
*
*@return The MainMethod value
*/
private boolean isMainMethod()
{
String name = getName();
if (!(name.equals("main") && node.isStatic()))
{
return false;
}
// Check for the void return type
ASTResultType result = (ASTResultType) node.jjtGetChild(0);
if (result.hasAnyChildren())
{
return false;
}
// Check the parameters
ASTMethodDeclarator decl = (ASTMethodDeclarator) node.jjtGetChild(1);
ASTFormalParameters params = (ASTFormalParameters) decl.jjtGetChild(0);
int childCount = params.jjtGetNumChildren();
if (childCount != 1)
{
return false;
}
ASTFormalParameter nextParam = (ASTFormalParameter) params.jjtGetChild(0);
ASTType type = (ASTType) nextParam.jjtGetChild(0);
if (type.getArrayCount() != 1)
{
return false;
}
Node child = type.jjtGetChild(0);
if (child instanceof ASTName)
{
ASTName nameNode = (ASTName) child;
if (nameNode.getName().equals("String") ||
nameNode.getName().equals("java.lang.String"))
{
return true;
}
}
return false;
}
/**
* Determine if this is a JUnit setUp method
*
*@return true if it is a JUnit setUp method
*/
private boolean isJUnitSetupMethod()
{
String name = getName();
return name.equals("setUp");
}
/**
* Determine if this is a JUnit test method
*
*@return true if it is a JUnit test method
*/
private boolean isJUnitTestMethod()
{
String name = getName();
return name.startsWith("test");
}
/**
* Determine if this is a JUnit tearDown method
*
*@return true if it is a JUnit tearDown method
*/
private boolean isJUnitTeardownMethod()
{
String name = getName();
return name.equals("tearDown");
}
/**
* Determine if this is a JUnit suite method
*
*@return true if it is a JUnit suite method
*/
private boolean isJUnitSuiteMethod()
{
String name = getName();
return name.equals("suite");
}
/**
* Returns the name of the method
*
*@return the name
*/
private String getName()
{
ASTMethodDeclarator decl = (ASTMethodDeclarator) node.jjtGetChild(1);
return decl.getName();
}
/**
* Guesses the name ofthe setter or getter's attribute
*
*@return the attribute name
*/
private String getAttributeName()
{
String name = getName();
if (!isGetter() && !isSetter() && !isAdder())
{
return "";
}
else if (name.startsWith("is"))
{
return name.substring(2);
}
else
{
return name.substring(3);
}
}
/**
* Gets the ParameterDescription attribute of the MethodAnalyzer object
*
*@param bundle Description of Parameter
*@param param Description of Parameter
*@return The ParameterDescription value
*/
private String getParameterDescription(FileSettings bundle, String param)
{
String pattern = "";
if (isSetter())
{
pattern = bundle.getString("setter.param.descr");
}
else if (isAdder())
{
pattern = bundle.getString("adder.param.descr");
}
else if (isMainMethod())
{
pattern = bundle.getString("main.param.descr");
}
else
{
pattern = bundle.getString("param.descr");
}
return createDescription(pattern, getAttributeName(), param);
}
/**
* Gets the ReturnDescription attribute of the MethodAnalyzer object
*
*@param bundle Description of Parameter
*@return The ReturnDescription value
*/
private String getReturnDescription(FileSettings bundle)
{
String pattern = "";
if (isJUnitSuiteMethod())
{
pattern = bundle.getString("junit.suite.return.descr");
}
else if (isGetter())
{
pattern = bundle.getString("getter.return.descr");
}
else
{
pattern = bundle.getString("return.descr");
}
return createDescription(pattern, getAttributeName(), "");
}
/**
* Description of the Method
*
*@param bundle Description of Parameter
*/
private void finishReturn(FileSettings bundle)
{
ASTResultType result = (ASTResultType) node.jjtGetChild(0);
if (result.hasAnyChildren())
{
if (!jdi.contains("@return"))
{
jdi.require("@return", getReturnDescription(bundle));
}
}
}
/**
* Description of the Method
*
*@param bundle Description of Parameter
*/
private void finishParameters(FileSettings bundle)
{
ASTMethodDeclarator decl = (ASTMethodDeclarator) node.jjtGetChild(1);
ASTFormalParameters params = (ASTFormalParameters) decl.jjtGetChild(0);
int childCount = params.jjtGetNumChildren();
for (int ndx = 0; ndx < childCount; ndx++)
{
ASTFormalParameter nextParam = (ASTFormalParameter) params.jjtGetChild(ndx);
ASTVariableDeclaratorId id = (ASTVariableDeclaratorId) nextParam.jjtGetChild(1);
if (!jdi.contains("@param", id.getName()))
{
jdi.require("@param", id.getName(), getParameterDescription(bundle, id.getName()));
}
}
}
/**
* Description of the Method
*
*@param bundle Description of Parameter
*/
private void finishExceptions(FileSettings bundle)
{
if ((node.jjtGetNumChildren() > 2) && (node.jjtGetChild(2) instanceof ASTNameList))
{
String exceptionTagName = "@exception";
try {
exceptionTagName = bundle.getString("exception.tag.name");
if (exceptionTagName.length() == 0)
exceptionTagName = "@exception";
else if (exceptionTagName.charAt(0) != '@')
exceptionTagName = "@" + exceptionTagName;
}
catch (MissingSettingsException mse) {
}
ASTNameList exceptions = (ASTNameList) node.jjtGetChild(2);
int childCount = exceptions.jjtGetNumChildren();
for (int ndx = 0; ndx < childCount; ndx++)
{
ASTName name = (ASTName) exceptions.jjtGetChild(ndx);
if (!jdi.contains("@exception", name.getName()) && !jdi.contains("@throws", name.getName()))
{
jdi.require(exceptionTagName, name.getName(), bundle.getString("exception.descr"));
}
}
}
}
/**
* Create the description string
*
*@param pattern Description of Parameter
*@param attribute Description of Parameter
*@param className Description of Parameter
*@return the expanded string
*/
private String createDescription(String pattern, String attribute, String className)
{
// Description of the constructor
Object[] nameArray = new Object[4];
nameArray[0] = attribute;
nameArray[1] = className;
if (node.isStatic())
{
nameArray[2] = "class";
}
else
{
nameArray[2] = "object";
}
nameArray[3] = lowerCaseFirstLetter(attribute);
String msg = MessageFormat.format(pattern, nameArray);
return msg;
}
/**
* Require the description
*
*@param bundle Description of Parameter
*@param className Description of Parameter
*/
private void requireDescription(FileSettings bundle, String className)
{
String pattern = "";
if (isJUnitSetupMethod())
{
pattern = bundle.getString("junit.setUp.descr");
}
else if (isJUnitTestMethod())
{
pattern = bundle.getString("junit.test.descr");
}
else if (isJUnitTeardownMethod())
{
pattern = bundle.getString("junit.tearDown.descr");
}
else if (isJUnitSuiteMethod())
{
pattern = bundle.getString("junit.suite.descr");
}
else if (isGetter())
{
pattern = bundle.getString("getter.descr");
}
else if (isSetter())
{
pattern = bundle.getString("setter.descr");
}
else if (isRunMethod())
{
pattern = bundle.getString("run.descr");
}
else if (isMainMethod())
{
pattern = bundle.getString("main.descr");
}
else if (isAdder())
{
pattern = bundle.getString("adder.descr");
}
else
{
pattern = bundle.getString("method.descr");
}
String msg = createDescription(pattern, getAttributeName(), className);
jdi.require("", msg);
}
/**
* Description of the Method
*
*@param value Description of Parameter
*@return Description of the Returned Value
*/
private String lowerCaseFirstLetter(String value)
{
if ((value == null) || (value.length() == 0))
{
return "";
}
if (value.length() == 1)
{
return value.toLowerCase();
}
return Character.toLowerCase(value.charAt(0)) + value.substring(1);
}
}